import { Graph, Node } from '@antv/x6';
import { v4 as guid } from "uuid";
import { CellType, SrmOrientation } from '../enums';
import { FieldUpdatedEvent, LaneConfig, SrmConfig } from '../models';
import { cornerRadio } from './cornerRadio';
import { Constance } from './nodes-util';
import { Logger } from 'src/service/logger';

export class SrmNode extends Node {
  static ShapeName = "srm";

  static register() {
    Graph.registerNode(SrmNode.ShapeName, SrmNode, true);
  }

  static unregister() {
    Graph.unregisterNode(SrmNode.ShapeName);
  }

  static getMeta(cfg?: SrmConfig): Node.Metadata {
    const { srm: _size } = Constance.sizes;
    const size = { width: cfg?.Width ?? _size.width, height: cfg?.Height ?? _size.height };
    const position = { x: cfg?.X ?? 0, y: cfg?.Y ?? 0 };

    const config: SrmConfig = {
      Id: cfg?.Id ?? guid(),
      Name: cfg?.Name ?? "堆垛机",
      Width: size.width,
      Height: size.height,
      X: position.x,
      Y: position.y,
      Plc: cfg?.Plc ?? {
        Ip: "",
        Port: 102,
        Interval: 1000,
      },
      Fields: cfg?.Fields ?? [],
      Lane: cfg?.Lane ?? {
        Orientation: SrmOrientation.L2R,
        MinColumn: 1,
        MaxColumn: 20,
        IsVisible: false,
        DoubleLine: false,
      },
      Status: cfg?.Status ?? {
        Id: guid(),
        Name: "Status",
        Description: "堆垛机状态",
        FontSize: 12,
        Visible: true,
        Maps: []
      },
      Type: CellType.Srm
    };

    const meta: Node.Metadata = {
      shape: SrmNode.ShapeName,
      size: size,
      position: position,
      id: config.Id,
      label: config.Name,
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          ...cornerRadio
        },
        plc: {
          text: `PLC[${config.Plc.Ip}:${config.Plc.Port}]`,
        },
        title: {
          text: config.Name,
        }
      },
      data: {
        cfg: config
      },
      zIndex: 2,
    };
    return meta;
  }

  update(cfg: SrmConfig) {
    this.attr('title/text', cfg.Name);
    this.attr("plc/text", `PLC[${cfg.Plc.Ip ?? "ip"}:${cfg.Plc.Port ?? "port"}]`);

    const { MinColumn, MaxColumn, IsVisible, DoubleLine, OffsetMin, OffsetMax, Orientation } = cfg.Lane;

    const gap = 1 / (MaxColumn - MinColumn + 1);
    const col = MinColumn;
    let colV = (col - MinColumn + 0.5) * gap;
    if (Orientation == SrmOrientation.R2L) {
      colV = 1 - colV;
    }
    this.attr("srm/refX", colV);

    if (IsVisible) {
      this.attr("topLane/visibility", 'visible');
      this.attr("bottomLane/visibility", 'visible');

      if (MaxColumn && MinColumn && MaxColumn >= MinColumn) {
        // 生成货架
        const w = 20;
        const h = 20;
        let str = "";
        const c = MaxColumn - MinColumn + 1;
        for (let i = 0; i < c; i++) {
          const l = i * w;
          if (DoubleLine) {
            str += `M${l},0L${l + w},0,L${l + w},${h}L${l},${h}L${l},0Z`;
            str += `M${l},${h}L${l + w},${h},L${l + w},${h * 2}L${l},${h * 2}L${l},${h}Z`;
          }
          else {
            str += `M${l},0L${l + w},0,L${l + w},${h}L${l},${h}L${l},0Z`;
          }
        }
        this.attr("topLane/refD", str);
        this.attr("bottomLane/refD", str);
      }
    } else {
      this.attr("topLane/visibility", 'hidden');
      this.attr("bottomLane/visibility", 'hidden');
    }
    this.data.cfg = cfg;
  }

  setColumn(column: number) {
    const { Plc } = this.data.cfg;
    const { Orientation, MinColumn, MaxColumn, OffsetMin, OffsetMax } = <LaneConfig>this.data.cfg.Lane;

    if (OffsetMin != undefined && OffsetMax != undefined && OffsetMax > OffsetMin) {
      const range = (OffsetMax - OffsetMin) * 1.01;
      const col = Math.min(OffsetMax, Math.max(OffsetMin, column));
      let colV = (col - OffsetMin) / range + 0.005;
      if (Orientation == SrmOrientation.R2L) {
        colV = 1 - colV;
      }
      this.transition("attrs/srm/refX", colV, {
        duration: Plc.Interval,
        progress: () => {
          const val = this.attr<number>("srm/refX");
          this.attr("tooltip/refX", val);
          this.attr("status/refX", val);
        },
        finish: () => {
        }
      });
    }
    else if (MaxColumn > MinColumn) {
      const gap = 1 / (MaxColumn - MinColumn + 1);
      const col = Math.min(MaxColumn, Math.max(MinColumn, column));
      let colV = (col - MinColumn + 0.5) * gap;
      if (Orientation == SrmOrientation.R2L) {
        colV = 1 - colV;
      }
      this.transition("attrs/srm/refX", colV, {
        duration: Plc.Interval,
        progress: () => {
          const val = this.attr<number>("srm/refX");
          this.attr("tooltip/refX", val);
          this.attr("status/refX", val);
        },
        finish: () => {
        }
      });
    }
  }

  fieldValueUpdated(e: FieldUpdatedEvent) {
    const { cfg }: { cfg: SrmConfig; } = this.data;
    this.data.Values = e.Values;
    const statusVal = e.Values["Status"];
    const status = cfg.Status.Maps.find(a => a.Key == statusVal);
    if (status) {
      const color = status.Color;
      this.attr("srm/fill", color);
      this.attr("status/fill", color);
      this.attr("status/text", `状态：${status.Description}`);
    } else {
      const color = "red";
      this.attr("srm/fill", color);
      this.attr("status/fill", color);
      this.attr("status/text", `状态：${statusVal}`);
    }

    if (cfg.Lane.SrmField) {
      let key = cfg.Lane.SrmField;
      if (Object.prototype.hasOwnProperty.call(e.Values, key)) {
        const CurrCol = e.Values[key];
        this.setColumn(CurrCol);
      }
    }

    const content = cfg.Fields.filter(a => a.Visible).map(f => `${f.Description ?? f.Name}:  ${e.Values[f.Name] ?? ""}`)
      .reduce((r, str) => r + "\n" + str, "");

    this.attr("tooltip/text", content);
  }

  getConfig(): SrmConfig {
    const { x, y } = this.position();
    const { width, height } = this.size();
    const cfg: SrmConfig = {
      ...this.data.cfg,
      Id: this.id,
      X: x,
      Y: y,
      Width: width,
      Height: height,
      Type: CellType.Srm,
    };
    return cfg;
  }

  logger?: Logger;
  setLogger(logger: Logger) {
    this.logger = logger;
  }

  bindPositionAndSizeChange() {
    this.on("change:position", ({ current }) => {
      const cfg = {
        ...this.data.cfg,
        X: current?.x,
        Y: current?.y
      };
      this.data.cfg = cfg;
    });
    this.on("change:size", ({ current }) => {
      const cfg = {
        ...this.data.cfg,
        Width: current?.width,
        Height: current?.height
      };
      this.data.cfg = cfg;
    });
  }
}

SrmNode.config(
  {
    markup: [
      {
        tagName: 'rect',
        selector: 'axis',
      },
      {
        tagName: "path",
        selector: 'topLane',
      },
      {
        tagName: "path",
        selector: 'bottomLane',
      },
      {
        tagName: 'text',
        selector: 'label',
      },
      {
        tagName: "image",
        selector: "srm"
      },
      {
        tagName: "text",
        selector: "tooltip",
      },
      {
        tagName: "text",
        selector: "plc",
      },
      {
        tagName: "text",
        selector: "title",
      }, {
        tagName: 'text',
        selector: "status",
      }
    ],
    attrs: {
      body: {

      },
      tooltip: {
        text: "",
        height: 20,
        refX: 0,
        refY: "50%",
        x: -25,
        y: -15,
        textAnchor: 'left',
        textVerticalAnchor: 'bottom',
        class: 'text-shadow-1',
        fill: "#ff0"
      },
      topLane: {
        refHeight: '50%',
        strokeWidth: 1,
        fill: 'rgba(230,230,230,0.2)',
        stroke: '#5F95FF',
        refWidth: '50%',
        refWidth2: 100,
        refY: '-50%',
        refY2: -50,
      },

      bottomLane: {
        refHeight: '50%',
        strokeWidth: 1,
        fill: 'rgba(230,230,230,0.2)',
        stroke: '#5F95FF',
        refWidth: '50%',
        refWidth2: 100,
        refY: '50%',
        refY2: 50,
      },
      axis: {
        refWidth: '100%',
        y: -5,
        height: 10,
        refY: "50%",
        fill: "#ddd",
        filter: {
          name: 'dropShadow',
          args: {
            dx: 2,
            dy: 2,
            blur: 3,
          },
        },
      },
      srm: {
        fill: "#ff0000",
        xlinkHref: '/assets/images/nodes/srm.png',
        height: 50,
        width: 200,
        refX: 0,
        refY: "50%",
        x: -50,
        y: -25,
        filter: {
          name: 'dropShadow',
          args: {
            dx: 2,
            dy: 2,
            blur: 3,
          },
        },
      },
      plc: {
        text: 'PLC',
        refX: '0%',
        refY: '50%',
        x: 0,
        y: 40,
        fill: 'rgba(255,255,255,0.25)',
        fontSize: 16,
        textAnchor: 'start',
        textVerticalAnchor: 'bottom',
        class: 'text-shadow-1',
      },
      group1: {
        fill: "#ff00ff",
      },
      title: {
        text: '堆垛机',
        refX: '100%',
        refY: '50%',
        x: -10,
        y: 40,
        fill: 'rgba(255,255,255,0.25)',
        fontSize: 20,
        textAnchor: 'end',
        textVerticalAnchor: 'bottom',
        class: 'text-shadow-1',
      },
      status: {
        text: '状态',
        height: 30,
        width: 50,
        refX: 0,
        refY: "50%",
        x: -20,
        y: 35,
        fill: 'rgba(255,255,255,0.75)',
        fontSize: 12,
        textAnchor: 'start',
        textVerticalAnchor: 'bottom',
        class: 'text-shadow-1',
      }
    },
  }
);